package priv.pfz.raft.peer;

import com.google.common.collect.Lists;
import priv.pfz.raft.peer.enums.PeerState;
import priv.pfz.raft.peer.model.OtherPeerInfo;
import priv.pfz.raft.peer.model.PeerConf;
import priv.pfz.raft.peer.model.PeerData;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author pengfangzhou
 * @date 2022/2/3 18:11
 */
public class PeerFactory {

    public static Peer createPeer(String peerName,
                                  List<String> allPeerNames,
                                  int maxElectionTimeout,
                                  int rpcInterval) {
        Peer peer = new Peer();

        PeerConf peerConf = new PeerConf();
        peerConf.setPeerName(peerName);
        peerConf.setAllPeerNames(allPeerNames);
        peerConf.setMajorityNum((allPeerNames.size() + 1) / 2);
        List<String> otherPeerNames = allPeerNames.stream()
                .filter(name -> !name.equals(peerName)).collect(Collectors.toList());
        peerConf.setOtherPeerNames(otherPeerNames);
        peerConf.setMaxElectionTimeout(maxElectionTimeout);
        peerConf.setRpcInterval(rpcInterval);

        PeerData peerData = new PeerData();
        peerData.setState(PeerState.STOPPED);
        peerData.setCurrentTerm(0);
        //以peer对象为锁初始化electionQueue
        peerData.setElectionQueue(new RaftEventQueue(peer));
        for (String otherPeerName : otherPeerNames) {
            OtherPeerInfo otherPeerInfo = new OtherPeerInfo();
            otherPeerInfo.setPeerName(otherPeerName);
            //以peer对象为锁初始化rpcQueue
            otherPeerInfo.setRpcQueue(new RaftEventQueue(peer));
            peerData.getOtherPeerInfoMap().put(otherPeerName, otherPeerInfo);
        }

        peer.setPeerConf(peerConf);
        peer.setPeerData(peerData);
        return peer;
    }

    public static List<Peer> createPeers(int peerCount,
                                         int maxElectionTimeout,
                                         int rpcInterval) {
        List<String> allPeerNames = Lists.newArrayList();
        for (int i = 0; i < peerCount; i++) {
            allPeerNames.add("S" + (i + 1));
        }

        List<Peer> peers = Lists.newArrayList();
        for (String peerName : allPeerNames) {
            peers.add(createPeer(peerName, allPeerNames, maxElectionTimeout, rpcInterval));
        }
        return peers;
    }

}
